FechaVersiónDescripción
04/09/20241.0.0Versión inicial.

 

Unidad 1. El Lenguaje Java y un poquito de Dart

1. El lenguaje Java

Java es un lenguaje de programación de propósito general, concurrente y orientado a objetos que fue diseñado específicamente para tener tan pocas dependencias de implementación como fuera posible. Su objetivo es permitir que los desarrolladores de aplicaciones escriban el programa una vez y lo ejecuten en cualquier dispositivo (conocido en inglés como WORA, o "write once, run anywhere"), lo que quiere decir que el código puede escribirse una sola vez y ser ejecutado en cualquier tipo de dispositivos (PC, móvil, etc.).

Las características de Java son:

1.1 Primer ejemplo

La aplicación más pequeña posible es la que simplemente imprime un mensaje en la pantalla.

Tradicionalmente, el mensaje suele ser "Hola Mundo!". Esto es justamente lo que hace el siguiente fragmento de código:

Hay que ver en detalle la aplicación anterior, línea a línea. Esas líneas de código contienen los componentes mínimos para imprimir Hola Mundo! en la pantalla. Es un ejemplo muy simple, que no instancia objetos de ninguna otra clase; sin embargo, accede a otra clase incluida en el JDK.

public class Main

Esta línea declara la clase Main. El nombre de la clase especificado en el fichero fuente se utiliza para crear un fichero nombredeclase.class en el directorio en el que se compila la aplicación. En este caso, el compilador creará un fichero llamado Main.class.

public static void main( String args[] )

Esta línea especifica un método que el intérprete Java busca para ejecutar en primer lugar. Igual que en otros lenguajes, Java utiliza una palabra clave main para especificar la primera función a ejecutar. En este ejemplo tan simple no se pasan argumentos.

System.out.println( "Hola Mundo!" );

Esta es la funcionalidad de la aplicación. Esta línea muestra el uso de un nombre de clase y método. Se usa el método println() de la clase out que está en el paquete System. El método println() toma una cadena como argumento y la escribe en el stream de salida estándar; en este caso, la ventana donde se lanza la aplicación. La clase PrintStream tiene un método instanciable llamado println(), que lo que hace es presentar en la salida estándar del Sistema el argumento que se le pase. En este caso, se utiliza la variable o instancia de out para acceder al método. El resultado sería el siguiente:

⚠Todas las instrucciones (creación de variables, llamadas a métodos, asignaciones) se deben finalizar con un punto y coma.

En el caso que no tengamos el IDE todavía instalado, podemos hacer usar el siguiente compilador online: https://replit.com/

Dentro de este podréis tener en la capa básica 44 proyectos o replit gratuitos.


 

1.2 Elementos básicos

1.2.1 Comentarios

En Java hay tres tipos de comentarios:

image-20210907131449925
image-20210907131544324
image-20210907131638052

Los dos primeros tipos de comentarios son los que todo programador conoce y se utilizan del mismo modo.

Los comentarios de documentación, colocados inmediatamente antes de una declaración (de variable o función), indican que ese comentario ha de ser colocado en la documentación que se genera automáticamente cuando se utiliza la herramienta de Java, javadoc, no disponible en otros lenguajes de programación. Este tipo de comentario lo veremos más adelante.

1.2.2 Identificadores

Los identificadores nombran variables, funciones, clases y objetos; cualquier cosa que el programador necesite identificar o usar.

Reglas para la creación de identificadores:

Serían identificadores válidos, por ejemplo:

y su uso sería, por ejemplo:

int contador; // crea variable de tipo int llamada contador

float sueldoNeto; // crea variable de tipo float llamada sueldoNeto

char letraDni; // crea variable de tipo char llamada letraDni

 

1.3 Tipos de datos

En Java existen dos tipos principales de datos:

Tipos de datos simples soportados por Java:

TipoDescripciónMemoria
ocupada
Rango de valores permitidos
byteNúmero entero de 1 byte1 byte-128 … 127
shortNúmero entero corto2 bytes-32768 … 32767
intNúmero entero4 bytes-2147483648 … 2147483647
longNúmero entero largo8 bytes-9223372036854775808 …
9223372036854775807
floatNúmero real en coma flotante de precisión simple32 bits±3,410-38 … ±3,41038
doubleNúmero real en coma flotante de precisión doble64 bits±1,710-308 … ±1,710308
charUn solo carácter2 bytes 
booleanValor lógico1 bittrue o false


Java no realiza una comprobación de los rangos.


Por ejemplo: si a una variable de tipo short con el valor 32.767 se le suma 1, sorprendentemente el resultado será -32.768 (no produce un error de tipo desbordamiento como en otros lenguajes de programación, sino que se comporta de forma cíclica).

Existe un tipo de dato compuesto llamado String que conviene conocer ya que permite representar texto. Más adelante veremos cómo se utiliza.

1.4 Declaración de variables

La forma básica de declarar (crear) una variable es la siguiente:

tipo identificador;

Por ejemplo, creamos una variable de tipo int llamada edad:

int edad;

Las variables pueden ser inicializadas en el momento de su declaración, es decir, se les puede dar un valor inicial al crearlas. Por ejemplo, creamos una variable de tipo int llamada edad y le asignamos 25 como valor inicial:

int edad = 25;

Esto es equivalente a primero declararla y luego asignarle el valor:

int edad; edad = 25;

También es posible declarar varias variables en una sola línea. Por ejemplo, creamos tres variables de tipo float llamadas precio1, precio2 y precio3:

float precio1f, precio2f, precio3f;

Esto es equivalente a:

float precio1f;

float precio2f;

float precio3f;

A su vez, también pueden inicializarse. Por ejemplo:

float precio1 = 7.0f, precio2 = 7.25f, precio3 = 0.5f;

Esto es equivalente a:

float precio1 = 7.0f;

float precio2 = 7.25f;

float precio3 = 0.5f;

Las constantes reales o en coma flotante se expresan con coma decimal y opcionalmente seguidos de un exponente. El valor puede finalizarse con una f o una F para indica el formato float (por defecto es double). Por ejemplo:

float f1 = 13.5;

Esto nos daría error puesto que la variable f1 es de tipo float mientras que 13.5 es double. Es necesario ponerle a 13.5 la f al final para indicar que es float.

Otros ejemplos a la hora de definir valores:

Como se verá más adelante cada tipo de dato primitivo tiene una clase correspondiente (Boolean, Character, Byte, Short, Integer, Long, Float y Double), llamadas wrappers, que definen también constantes y métodos útiles.

En resumen la declaración de variables sigue el siguiente patrón:

🎓tipo identificador [ = valor][,identificador [= valor] ...];

Es decir, es obligatorio indicar el tipo y el identificador (además de terminar en punto y coma como todas las instrucciones). Opcionalmente (indicado entre corchetes) se puede inicializar y/o se pueden declarar más variables.


⚠ Si una variable no ha sido inicializada, Java le asigna un valor por defecto.


Este valor es:

Es una buena práctica inicializar siempre todas las variables.

 

Palabras clave

abstractcontinuefornewswitch
booleandefaultgotonullsynchronized
breakdoifpackagethis
bytedoubleimplementsprivatethreadsafe
byvalueelseimportprotectedthrow
caseextendsinstanceofpublictransient
catchfalseintreturntrue
charfinalinterfaceshorttry
classfinallylongstaticvoid
constfloatnativesuperwhile

Palabras reservadas

Además, el lenguaje se reserva unas cuantas palabras más, pero que hasta ahora no tienen un cometido específico. Son:

castuturegenericinner
operatorouterrestvar

1.4.1 Ámbito de una variable

🎓 El ámbito de una variable es la porción del programa donde dicha variable puede utilizarse.

El ámbito de una variable depende del lugar del programa donde es declarada, pudiendo pertenecer a cinco categorías distintas.

  1. Variable global.

  2. Variable local.

  3. Atributo.

  4. Parámetro de un método.

  5. Parámetro de un tratador de excepciones.

Por ahora utilizaremos solo variables locales nunca variables globales. Las demás categorías las veremos en posteriores unidades.

1.4.2 Variables locales

🎓 Una variable local se declara dentro del cuerpo de un método de una clase y es visible únicamente dentro de dicho método.

Se puede declarar en cualquier lugar del cuerpo, incluso después de instrucciones ejecutables, aunque es una buena costumbre declararlas justo al principio.

También pueden declararse variables dentro de un bloque con llaves {...}. En ese caso, sólo serán “visibles” dentro de dicho bloque.

Por ejemplo (No es necesario entender lo que hace el programa) :

En este ejemplo existe una variable local: int i; únicamente puede utilizarse dentro del bloque main donde fué creada.

1.4.3 Constantes (final)

Al declarar una variable puede utilizarse la palabra reservada final para indicar que el valor de la variable no podrá modificarse (es una constante).

Por ejemplo, creamos variable constante tipo int llamada x con valor 18:

final int x = 18;

Por ejemplo, creamos variable constante tipo float llamada pi con valor 3.14:

final float pi = 3.14;

Si posteriormente intentamos modificar sus valores se producirá un error y Java nos avisará de que no es posible.

x = 20; // no permitido, produce error pi = 7; // no permitido, produce error


⚠ Por lo tanto una variable precedida de la palabra final se convierte en una constante. O lo que es lo mismo, para definir una constante en Java deberemos preceder su declaración de la palabra reservada final.

 

1.5 Operadores

Los operadores son una parte indispensable de la programación ya que nos permiten realizar cálculos matemáticos y lógicos, entre otras cosas. Los operadores pueden ser:

Aritméticos : sumas, restas, etc.

Relacionales : menor, menor o igual, mayor, mayor o igual, etc.

Lógicos : and, or, not, etc.

Bits : prácticamente no los utilizaremos en este curso.

Asignación : =

1.5.1 Aritméticos

OperadorFormatoDescripción
+op1 + op2Suma aritmética de dos operandos.
-op1 - op2
-op1
Resta aritmética de dos operandos. Cambio de signo.
*op1 * op2Multiplicación de dos operandos
/op1 / op2División entera de dos operandos
%op1 % op2Resto de la división entera ( o módulo)
++++op1
op1++
Incremento unitario
----op1
op1--
Decremento unitario

El operador - puede utilizarse en su versión unaria ( - op1 ) y la operación que realiza es la de invertir el signo del operando.

Los operadores ++ y -- realizan un incremento y un decremento unitario respectivamente. Es decir:

x++ equivale a x = x + 1

x-- equivale a x = x - 1

Los operadores ++ y -- admiten notación postfija y prefija:

Los operadores incrementales suelen utilizarse a menudo en los bucles (estructuras repetitivas). Lo veremos más adelante.

1.5.2 Relacionales

OperadorFormatoDescripción
>op1 > op2Devuelve true (cierto) si op1 es mayor que op2
<op1 < op2Devuelve true (cierto) si op1 es menor que op2
>=op1 >= op2Devuelve true (cierto) si op1 es mayor o igual que op2
<=op1<= op2Devuelve true (cierto) si op1 es menor o igual que op2
==op1 == op2Devuelve true (cierto) si op1 es igual a op2
!=op1 != op2Devuelve true (cierto) si op1 es distinto de op2

Los operadores relacionales actúan sobre valores enteros, reales y caracteres (char); y devuelven un valor del tipo boolean (true o false).

Ejemplo:

Resultado de ejecución:

image-20210907174844618

1.5.3 Lógicos

OperadorFormatoDescripción
&&op1 && op2Y lógico. Devuelve true (cierto) si son ciertos op1 y op2
||op1 || op2O lógico. Devuelve true (cierto) si son ciertos op1 o op2
!! op1Negación lógica. Devuelve true (cierto) si es false op1.

Estos operadores actúan sobre operadores o expresiones lógicas, es decir, aquellos que se evalúan a cierto o falso (true / false).

Resultado de ejecución:

image-20210907180405002

1.5.4 Asignación

El operador de asignación es el símbolo igual: =


variable = expresión


Es posible combinar el operador de asignación con otros operadores para, de forma abreviada, realizar un cálculo y asignarlo a una variable:

OperadorFormatoDescripción
+=op1 += op2op1 = op1 + op2
-=op1 -= op2op1 = op1 - op2
*=op1 *= op2op1 = op1 * op2
/=op1 /= op2op1 = op1 / op2
%=op1 %= op2op1 = op1 % op2
&=op1 &= op2op1 = op1 & op2
|=op1 |= ope2op1 = op1 | ope2
^=op1 ^= op2op1 = op1 ^ op2
>>=op1 >>= op2op1 = op1 >> op2
<<=op1 <<= op2op1 = op1 << op2
>>>=op1 >>>= op2op1 = op1 >>> op2

1.5.5 Expresiones

Una expresión es la combinación de varios operadores y operandos. Por ejemplo, tenemos las siguientes expresiones:

7 + 5 * 4 - 2 10 + (1 % 5) (7 * x) <= N etc.

El lenguaje Java evalúa las expresiones aplicando los operadores uno a uno siguiendo un orden específico. Este orden se detalla en el siguiente punto.

1.5.6 Precedencia de operadores

Indica el orden en el que se evalúan los operadores en una expresión. No es necesario saberse toda la lista de memoria, pero es importante conocer al menos los más utilizados: matemáticos, relacionales, lógicos y de asignación.

Algunos de estos operadores los veremos en unidades posteriores, ahora mismo no es necesario que sepas qué hacen.

  1. Operadores postfijos: [ ] . (paréntesis)

  2. Operadores unarios: ++expr, --expr, -expr, ~ !

  3. Creación o conversión de tipo: new (tipo)expr

  4. Multiplicación y división: *, /, %

  5. Suma y resta: +, -

  6. Desplazamiento de bits: <<, >>, >>>

  7. Relacionales: <, >, <=, >=

  8. Igualdad y desigualdad: ==, !=

  9. AND a nivel de bits: &

  10. AND lógico: &&

  11. XOR a nivel de bits: ^

  12. OR a nivel de bits: |

  13. OR lógico: ||

  14. Operador condicional: ? :

  15. Asignación: =, +=, -=, *=, /=, %=, ^=, &=, |=, >>=, <<=

 


1.6 Conversión de tipos

1.6.1 Casting

La conversión entre tipos primitivos se realiza mediante el casting. Java proporciona dos tipos de casting: implícito y explícito. El implícito se realiza automáticamente, mientras que el explícito la tenemos que escribir nosotros.

Casting implícito

El compilador realiza automáticamente el casting implícito cuando el tipo al que se ha de convertir un dato es más amplio que el tipo original.

Es decir, Java hará el casting implícito automáticamente cuando convertimos:

casting

Por ejemplo:

Si tratamos de hacer un casting implícito al revés, el compilador nos dará un error:


El casting con los tipos boolean y String no se puede realizar.


Casting explicito

Hemos visto que el casting implícito no se puede realizar cuando queremos convertir a un tipo más estrecho (por ejemplo, convertir de float a int, ya que se pierden los decimales). Pero a veces necesitamos hacerlo, sabiendo que vamos a perder precisión. En este caso tenemos que explicitar el casting.

Para realizar un casting explícito, se debe escribir el tipo al que se quiere convertir entre paréntesis, justo antes del valor que se quiere convertir.

(tipo) valor

Los siguientes ejemplos ilustran el uso del casting explícito:

1.6.2 Conversión textual

Además de las conversiones con casting, Java incorpora una serie de métodos para hacer otras conversiones.

Concatenación

Se puede convertir cualquier valor en un String sólo concatenando con un String vacío "".

 

String.valueOf()

De forma equivalente a la concatenación, se puede utilizar el método String.valueOf () para convertir a String.

 

charAt()

Lógicamente, no podemos convertir un String en un char, ya que el String puede tener varios caracteres. Pero podemos usar el método Char () para obtener un caracter que esté en una determinada posición.

Hay que tener en cuenta que las posiciones empiezan por 0.

 

Character.getNumericValue()

En el punto anterior hemos visto que si hacemos el casting implícito para convertir un char en un int, obtenemos el valor Unicode del carácter.

Si queremos obtener el valor que representa el caracter se puede hacer con el método Character.getNumericValue ().

 

parseInt() y parseFloat()

Para obtener el valor numérico representado por un String podemos utilizar parseInt () o parseFloat ().

 

1.7 La clase Math

Se echan de menos operadores matemáticos más potentes en Java. Por ello se ha incluido una clase especial llamada Math dentro del paquete java.lang.

Esta clase posee muchos métodos muy interesantes para realizar cálculos matemáticos complejos como cálculo de potencias, raíces cuadradas, valores absolutos, seno, coseno, etc.

Por ejemplo:

También posee constantes como:

Algunos ejemplos de otros métodos: image-20210907184818918

1.8 Literales

A la hora de tratar con valores de los tipos de datos simples (y Strings) se utiliza lo que se denomina “literales”. Los literales son elementos que sirven para representar un valor en el código fuente del programa.

En Java existen literales para los siguientes tipos de datos:

 

1.8.1 Literales lógicos

Son únicamente dos, las palabras reservadas true y false.

Ejemplo: boolean activado = false;

 

1.8.2 Literales enteros

Los literales de tipo entero: byte, short, int y long pueden expresarse en decimal (base 10), octal (base 8) o hexadecimal (base 16). Además, puede añadirse al final del mismo la letra L para indicar que el entero es considerado como long (64bits).

En Java, el compilador identifica un entero decimal (base 10) al encontrar un número cuyo primer dígito es cualquier símbolo decimal excepto el cero (del 1 al 9). A continuación pueden aparecer dígitos del 0 al 9.

La letra L al final de un literal de tipo entero puede aplicarse a cualquier sistema de numeración e indica que el número decimal sea tratado como un entero largo (de 64 bits). Esta letra L puede ser mayúscula o minúscula, aunque es aconsejable utilizar la mayúscula ya que de lo contrario puede confundirse con el dígito uno (1) en los listados.

Ejemplo: long max1 = 9223372036854775807L; //valor máximo para un entero largo

 

1.8.3 Literales reales

Los literales de tipo real sirven para indicar valores float o double. A diferencia de los literales de tipo entero, no pueden expresarse en octal o hexadecimal.

Existen dos formatos de representación: mediante su parte entera, el punto decimal ( . ) y la parte fraccionaria; o mediante notación exponencial o científica:

Ejemplos equivalentes: 3.1415 0.31415e1 .31415e1 0.031415E+2 .031415e2 314.15e-2 31415E-4

Al igual que los literales que representan enteros, se puede poner una letra como sufijo. Esta letra puede ser una F o una D (mayúscula o minúscula indistintamente).

F --> Trata el literal como de tipo float.

D --> Trata el literal como de tipo double.

Ejemplo:

3.1415F

.031415d

 

1.8.4 Literales carácter

Los literales de tipo carácter se representan siempre entre comillas simples. Entre las comillas simples puede aparecer:

Un símbolo (letra) siempre que el carácter esté asociado a un código Unicode. Ejemplos: ‘a’ , ‘B’ , ‘{‘ , ‘ñ’ , ‘á’ .

Una “secuencia de escape”. Las secuencias de escape son combinaciones del símbolo contrabarra \ seguido de una letra, y sirven para representar caracteres que no tienen una equivalencia en forma de símbolo.

Las posibles secuencias de escape son:

\n -----> Nueva Linea.

\t -----> Tabulador.

\r -----> Retroceso de Carro.

\f -----> Comienzo de Pagina.

\b -----> Borrado a la Izquierda.

\\----> El carácter barra inversa ( \ ).

\' -----> El carácter prima simple ( ' ).

\" -----> El carácter prima doble o bi-prima ( " ).

Por ejemplo:

Para imprimir una diagonal inversa se utiliza: \\

Para imprimir comillas dobles en un String se utiliza: \"

 

1.8.5 Literales cadenas

Los Strings o cadenas de caracteres no forman parte de los tipos de datos elementales en Java, sino que son instanciados a partir de la clase java.lang.String, pero aceptan su inicialización a partir de literales de este tipo, por lo que se tratan en este punto.


⚠ Un literal de tipo string va encerrado entre comillas dobles ( “ ) y debe estar incluido completamente en una sola línea del programa fuente (no puede dividirse en varias líneas).


Entre las comillas dobles puede incluirse cualquier carácter del código Unicode (o su código precedido del carácter \ ) además de las secuencias de escape vistas anteriormente en los literales de tipo carácter.

Así, por ejemplo, para incluir un cambio de línea dentro de un literal de tipo string deberá hacerse mediante la secuencia de escape \n :

Ejemplo:

System.out.println(”Primera línea\nSegunda línea del string\n”);

System.out.println(”Hola”);

La visualización del string anterior mediante println() produciría la siguiente salida por pantalla:

Primera línea

Segunda línea del string

Hola

 

La forma de incluir los caracteres: comillas dobles ( “ ) y contrabarra ( \ ) es mediante las secuencias de escape \” y \\ respectivamente (o mediante su código Unicode precedido de \ ).


📣 Si el string es demasiado largo y debe dividirse en varias líneas en el fichero fuente, puede utilizarse el operador de concatenación de strings (+) de la siguiente forma:

”Este String es demasiado largo para estar en una línea del ” +

”fichero fuente y se ha dividido en dos.”


 

1.9 Salida y Entrada Estándar

1.9.1 Salida estándar

Ya hemos visto el uso de System.out para mostrar información por pantalla:

La utilización de System.err sería totalmente análoga para enviar los mensajes producidos por errores en la ejecución (es el canal que usa también el compilador para notificar los errores encontrados).

Por ejemplo, para presentar el mensaje de saludo habitual por pantalla, y después un mensaje de error, tendríamos la siguiente clase (aunque en realidad toda la información va a la consola de comandos donde estamos ejecutando el programa):

y la salida sería la siguiente:

image-20210907194930581

También pueden imprimirse variables de cualquier tipo, así como combinaciones de texto y variables concatenadas con el operador +

Y la salida sería la siguiente:

image-20210907195340470

 

1.9.2 Entrada estándar

La entrada estándar (leer información del teclado, escrita por el usuario) es un poco más compleja. Hay varias formas de hacerlo pero la más sencilla es utilizar la clase Scanner.

Siempre que queramos leer información del teclado primero tendremos que declarar un objeto Scanner que lea de la entrada estándar System.in así:

Scanner sc= new Scanner(System.in);

🧷 NOTA: En este ejemplo hemos creado un objeto Scanner llamado sc pero podríamos ponerle cualquier nombre.

 

Ahora podremos utilizar reader tantas veces como queramos para leer información del teclado. Por ejemplo:

String texto = sc.nextLine();

El método sc.nextLine() recogerá el texto que el usuario escriba por teclado (hasta presionar la tecla Intro) y lo guardará en texto (de tipo String).

Existen mucho otros métodos según el tipo de dato que se quiera leer:


⚠ No existen métodos de la clase Scanner para obtener directamente booleanos ni para obtener un solo carácter.



📣 IMPORTANTE: Para poder utilizar la clase Scanner es necesario importarla desde el paquete java.util de Java. Es decir, arriba del todo (antes del public class… ) hay que escribir la siguiente sentencia:

import java.util.Scanner;


Ejemplo en el que leemos una cadena de texto y la mostramos por pantalla:

Salida:

image-20210907204726235

Ejemplo en el que leemos un valor tipo double. El programa pide al usuario que introduzca el radio de un círculo, luego calcula su área y circunferencia, por último lo muestra por pantalla.

Salida:

 

image-20210907205409638

1.10 Strings (cadenas de caracteres)

Hasta ahora hemos trabajado con el tipo de dato String el cual nos permite almacenar una cadena de caracteres. Para poder trabajar con String disponemos de una serie de funciones que nos van a ayudar a trabajar con ellos.

 

Aquí podemos ver una serie de ejemplos de estos, comentado al lado de cada uno de ellos podéis ver el resultado:

 

2. El Lenguaje Dart

Dart (originalmente llamado Dash) es un lenguaje de programación de código abierto, desarrollado por Google. Fue revelado en la conferencia goto; en Aarhus, Dinamarca el 10 de octubre de 2011.2 El objetivo de Dart no es reemplazar JavaScript como el principal lenguaje de programación web en los navegadores web, sino ofrecer una alternativa más moderna. El espíritu del lenguaje puede verse reflejado en las declaraciones de Lars Bak, ingeniero de software de Google, que define a Dart como un “lenguaje estructurado pero flexible para programación Web”.

 

2.1 Primer ejemplo

Como se puede observar, la entrada al programa principal en dart se realiza también a través del método main de tipo void.

2.2 Elementos básicos

2.2.1. Comentarios

Al igual que en Java los comentarios en Dart se realizan de igual forma:

2.2.2 Identificadores

Las reglas para el nombrado de variables son las siguientes:

2.3 Tipos de datos

El lenguaje Dart tiene soporte especial para lo siguiente:

 

Números

https://dart.dev/language/built-in-types#numbers

Los números de Dart vienen en dos tipos:

Ambos inty doubleson subtipos de num. El tipo num incluye operadores básicos tales como el de los operadores, -, /, y *, y también es donde encontrará abs(),ceil(), y floor(), entre otros métodos. (Los operadores de apto, como el de la intclase.) Si num y sus subtipos no tienen lo que estás buscando, la biblioteca de dardos:math podría.

A continuación, se muestran algunos ejemplos de definición:

Cadenas

El tipo para declarar variables que puedan contener cadenas de texto es String [ver documentación]. Estas pueden ir encerradas entre comillas simples o entre comillas dobles:

2.4 Declaración de variables

Para declarar una variable en Dart, la sintaxis básica es: Tipo nombre_variable [= valor]; Se pueden declarar varias variables en la misma línea con la siguiente sintaxis: Tipo nombre_variable1 [[=valor1][, nombre_variable2 [=valor2]…]; Puedes copiar el siguiente código en DartPad para comprobar el funcionamiento (en próximos apartados se estudiarán los tipos permitidos en Dart):

Tipado débil

Las variables que hemos explicado anteriormente utilizan un tipo en la declaración que define su dominio, pero puede haber casos muy concretos en los que no sepamos qué tipo de dato va a recibir una función, por ejemplo, a la hora de consumir una API. Para estos casos, tenemos dos opciones:

  1. Declarar la variable con el tipo var:

    El programa nos debe mostrar que el tipo de la variable es int, porque al asignar el valor en la declaración, el tipo cambia al del valor asignado. En realidad, nos dará error porque al asignarse el tipo int, estamos incurriendo en un error al intentar asignarle un String.

    Si el valor es asignado después de la declaración, podemos asignar valores de diferentes tipos a lo largo de la ejecución del programa y en cada momento cambiará el tipo de la variable:

    En el caso anterior mostrará: null String int

  2. Declarar la variable como dynamic:

    Tiene exactamente el mismo funcionamiento que utilizar var sin asignar el valor en la declaración. Tanto si utilizamos var como dynamic, podemos utilizar métodos y propiedades del tipo en tiempo de ejecución de la variable, tal y como se puede comprobar ejecutando el código del último ejemplo, donde se invoca al método startsWith(…) del tipo String.

 

Nullables

A partir de la versión 2.19 de Dart, se introdujo una característica existente en otros lenguajes y que evita algunos errores en tiempo de ejecución. Esta característica son las variables Nullables o que tienen la capacidad de aceptar valores nulos. El siguiente ejemplo, en el que se suman dos valores enteros es, para una versión de Dart sin comprobación de nulos, correcto y se compila sin errores:

¿Cuál es el problema? Al intentar sumar la variable operando2, con valor nulo, a la variable operando1, se produce un error de ejecución. En las versiones actuales, por defecto, las variables no permiten valores nulos, y es preciso asignarles valor en algún punto del programa para que nos permita compilarlo.

Para poder declarar variables que acepten valores nulos, es necesario hacerlo de forma explicita mediante el operador ?. Esto sería válido, por ejemplo, para poder asignar a una variable el valor de una función que pueda devolver null.

Operador de aserción !

En determinadas ocasiones querremos asignar el resultado de expresiones a una variable no nullable, pero el compilador, al no ser capaz de prever si el valor de la expresión es o no nulo, arroja un error de compilación aunque nuestro código sea correcto y hayamos creado la expresión de forma que siempre devuelva un valor no nulo:

En el ejemplo anterior, al ser el tipo de devolución de la función maximo un valor entero nullable, en el que la función podría devolver un nulo, el compilador detectará un error semántico al asignar el valor de retorno a una variable no nullable, y abortará la ejecución a pesar de que la función nunca devolverá null. La forma de evitar esto en expresiones en las que estamos seguros de que se devuelve un valor correcto es añadiendo un operador de aserción (carácter !) tras la expresión:

2.4.1 Declaración de constantes

Para declarar valores que no van a cambiar durante la ejecución del programa, Dart utiliza las palabras reservadas const y final, que funcionan de la misma manera en el caso de los tipos simples.

Por convención, las constantes suelen escribirse en mayúsculas, aunque no es una norma del lenguaje. El tipo no es obligatorio ponerlo, aunque sí aconsejable.

2.5 Concatenación

Para concatenar cadenas de texto, Dart nos ofrece tres mecanismos:

Mediante operador +: concatena dos cadenas. A diferencia de otros lenguajes en los que se pueden concatenar expresiones de cadena con otras de tipos diferentes, en Dart únicamente se permite concatenar String, teniendo que hacer un casting (toString()) para concatenar tipos diferentes:

Mediante interpolación de cadenas: Anteponiendo el símbolo de dólar al nombre de la variable o constante dentro de la cadena($variable). En este caso, el tipo de la variable sí puede ser diferente de String:

Encerrando la expresión entre llaves y anteponiendo el símbolo de dólar (${expresión}):

2.6 Operadores

2.6.1 Operadores aritméticos

Para realizar operaciones de tipo aritmético, Dart utiliza los mismos operadores que C o Java:

La operación a/=b se ha comentado porque al devolver a/b un valor double, genera un error cuando se intenta asignar a la variable a, que es int. Si a y b estuviesen declaradas como double, la operación sería correcta.

2.6.2 Operadores relacionales

Son los operadores que vamos a utilizar para realizar comparaciones:

A la hora de comparar objetos, si se quiere averiguar si dos instancias son el mismo objeto, se utiliza el método identical() en lugar de ==.

2.6.3 Operadores lógicos

Los operadores lógicos son los mismos que en C:

2.7 Conversión de tipos (Casting)

Hacer un casting a un dato, consiste en hacer una conversión de su tipo para convertirlo en otro diferente. A diferencia de lo que ocurre en otros lenguajes, en Dart no existe la conversión implícita. Teniendo que indicar de forma explícita el tipo al que queremos convertir. Por ejemplo, no es posible concatenar una variable numérica a una cadena, como se muestra en el siguiente ejemplo en Java:

O asignar un valor de un tipo diferente a una variable como podríamos hacer en C:

Para poder llevar a cabo las conversiones en Dart, podremos hacerlo de tres formas diferentes:

  1. Utilizando un método del dato que nos permita convertir al tipo deseado. El siguiente ejemplo, que utiliza el método toString() [ver documentación], es equivalente al ejemplo mostrado en Java:

    El siguiente ejemplo, que utiliza el método toDouble() [ver documentación], es equivalente al código en C:

  2. Utilizando la función estática parse(String) [ver documentación], propia del tipo para parsear (convertir) un String al dato, previo análisis para comprobar que el formato es válido. Si queremos convertir, por ejemplo, un int a double, utilizamos el método desde el tipo double, convirtiendo el int a String, como se muestra en el siguiente ejemplo equivalente al código C:

    El tipo String no tiene método parse, porque la conversión se hace utilizando el método toString() del dato.

  3. Utilizando el método tryParse(String) [ver documentación], que funciona como la anterior, pero en lugar de lanzar una excepción si se le pasa un parámetro incorrecto, devuelve null. Se puede combinar con el operador ?? que se estudiará en el apartado de expresiones condicionales.

2.8 Entrada y salida estándar

La entrada y salida estándar en dart, al igual que en cualquier lenguaje, es dependiente del sistema operativo y para nuestro caso la entrada es por teclado y la salida por pantalla.

Para la salida, ya hemos visto cual es el método que nos es necesario, print, en ejemplos anteriores.

Para la entrada lo recogemos con el método stdin.readLineSync() que por defecto recoge una cadena de texto desde el teclado. Si luego necesitamos que sea un entero, deberemos parsearlo.